/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package dieci.database.returns;

import dieci.database.PersistentObject;
import dieci.database.SessionFactoryUtil;
import dieci.hibernate.HibReturn;
import dieci.hibernate.HibReturnDetails;
import dieci.managers.ordermanager.OrderManager;
import dieci.managers.supplier.SupplierManager;
import dieci.system.Order;
import dieci.system.Return;
import dieci.system.ReturnDetails;
import dieci.system.Supplier;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.hibernate.Session;
import org.hibernate.criterion.Restrictions;

/**
 *
 * @author Blanco
 */
public class ReturnHibernateDAO implements ReturnDAO 
{
    private static Logger logger = Logger.getLogger("ReturnDAO.log");
    private SupplierManager supplierManager = new SupplierManager();
    private OrderManager orderManager = new OrderManager();
    
    @Override
    public List<Return> list()
    {
        List<Return> returns = new ArrayList<>();

        Session session = SessionFactoryUtil.getInstance().getCurrentSession();
        try {
            session.beginTransaction();

            List<HibReturn> hibReturns = session.createCriteria(HibReturn.class).list();
            for (HibReturn dbReturn : hibReturns) {
                Set<ReturnDetails> details = new HashSet<>();
                for (HibReturnDetails hibReturnDetails : dbReturn.getDetails()) {
                    details.add(new ReturnDetails(hibReturnDetails.getId().getProductId(),
                            hibReturnDetails.getAmount()));
                }
                Supplier supplier = supplierManager.findById(dbReturn.getSupplierId());
                Order order = orderManager.find(dbReturn.getOrderId());
                Return returnOb = new Return(supplier, order, dbReturn.getReturnDate(), details);
                returnOb.setReturnId(dbReturn.getReturnId());
                returns.add(returnOb);
            }

            return returns;
        }
        catch (Exception e) {

            logger.log(Level.INFO, "Error listando", e.getMessage());

            throw new IllegalStateException("Error al listar", e);
        }
        finally {
            if (session != null && session.isOpen()) {

                session.close();
            }
        }
    }

    @Override
    public Return findByReturnId(long id)
    {
        Return result = null;
        Session session = SessionFactoryUtil.getInstance().getCurrentSession();
        try {
            session.beginTransaction();

            HibReturn hibReturn = (HibReturn) session.createCriteria(HibReturn.class).add(Restrictions.eq("returnId", id)).uniqueResult();
            if (hibReturn != null) {
                Set<ReturnDetails> details = new HashSet<>();
                for (HibReturnDetails detail : hibReturn.getDetails()) {

                    ReturnDetails p = new ReturnDetails(detail.getId().getProductId(), detail.getAmount());
                    p.setReturnId(detail.getId().getReturnId());
                    details.add(p);
                }
                Supplier supplier = supplierManager.findById(hibReturn.getSupplierId());
                Order order = orderManager.find(hibReturn.getOrderId());
                result = new Return(supplier, order,
                        hibReturn.getReturnDate(), details);
                result.setReturnId(hibReturn.getReturnId());
            }

        }
        catch (Exception e) {
            throw new IllegalStateException("Error al buscar por articulo", e);
        }
        finally {
            if (session != null && session.isOpen()) {

                session.close();
            }
        }

        return result;
    }

    @Override
    public void delete(PersistentObject object)
    {
        Session session = null;

        Return returns = (Return) object;
        Return found = findByReturnId(returns.getReturnId());
        try {
            session = SessionFactoryUtil.getInstance().getCurrentSession();

            session.beginTransaction();

            if (found != null) {
                //DELETE
                returns.setReturnId(found.getReturnId());

                Set<HibReturnDetails> hibReturnDetailss = new HashSet<>();
                for (ReturnDetails detail : returns.getDetails()) {
                    HibReturnDetails p = new HibReturnDetails(detail, returns.getReturnId());
                    hibReturnDetailss.add(p);
                }
                HibReturn hibReturn = new HibReturn(returns.getReturnId(), (Return) returns);
                hibReturn.setDetails(hibReturnDetailss);
                session.delete(hibReturn);

            }

            session.getTransaction().commit();

        }
        catch (Exception e) {
            if (session != null) {
                session.getTransaction().rollback();
            }
            throw new IllegalStateException("Error al eliminar", e);
        }
        finally {
            if (session != null && session.isOpen()) {

                session.close();
            }
        }
    }

    @Override
    public void saveOrUpdate(PersistentObject object)
    {
        Session session = null;

        Return returns = (Return) object;
        Return found = null;

        if (returns.getReturnId() > 0) {
            found = findByReturnId(returns.getReturnId());
        }

        try {
            session = SessionFactoryUtil.getInstance().getCurrentSession();

            session.beginTransaction();

            if (found != null) {
                //UPDATE
                returns.setReturnId(found.getReturnId());

                Set<HibReturnDetails> hibReturnDetailss = new HashSet<>();
                for (ReturnDetails detail : returns.getDetails()) {
                    HibReturnDetails d = new HibReturnDetails(detail, returns.getReturnId());
                    hibReturnDetailss.add(d);
                }
                HibReturn hibReturn = new HibReturn(returns.getReturnId(), (Return) returns);
                hibReturn.setDetails(hibReturnDetailss);
                session.saveOrUpdate(hibReturn);

            }
            else {
                //NEW
                HibReturn hibReturn = new HibReturn(returns);

                // generate new id for the orderuct
                session.save(hibReturn);
                // add the details
                for (ReturnDetails detail : returns.getDetails()) {
                    hibReturn.getDetails().add(
                            new HibReturnDetails(detail, hibReturn.getReturnId()));
                }

                // If the enty already exist update it.
                session.saveOrUpdate(hibReturn);
            }

            session.getTransaction().commit();

        }
        catch (Exception e) {
            if (session != null) {
                session.getTransaction().rollback();
            }
            logger.log(Level.INFO, "Error al guardar o actualizar " + e.getMessage());
            throw new IllegalStateException("Error al guardar o actualizar", e);
        }
        finally {
            if (session != null && session.isOpen()) {

                session.close();
            }
        }
    }

    @Override
    public List<Return> findByReturnDateRange(Date start, Date end)
    {
        List<Return> returns = new ArrayList<>();

        Session session = SessionFactoryUtil.getInstance().getCurrentSession();
        try {
            session.beginTransaction();

            List<HibReturn> hibReturns = session.createCriteria(HibReturn.class).add(Restrictions.between("returnDate", start, end)).list();
            for (HibReturn dbReturn : hibReturns) {
                Set<ReturnDetails> details = new HashSet<>();
                for (HibReturnDetails hibReturnDetails : dbReturn.getDetails()) {
                    details.add(new ReturnDetails(hibReturnDetails.getId().getProductId(),
                            hibReturnDetails.getAmount()));
                }
                Supplier supplier = supplierManager.findById(dbReturn.getSupplierId());
                Order order = orderManager.find(dbReturn.getOrderId());
                Return returnOb = new Return(supplier, order, dbReturn.getReturnDate(), details);
                returnOb.setReturnId(dbReturn.getReturnId());
                returns.add(returnOb);
            }

            return returns;
        }
        catch (Exception e) {

            logger.log(Level.INFO, "Error listando devoluciones por fecha", e.getMessage());

            throw new IllegalStateException("Error al listar", e);
        }
        finally {
            if (session != null && session.isOpen()) {

                session.close();
            }
        }
    }

    @Override
    public List<Return> findBySupplierName(String supplierName)
    {
        List<Return> returns = new ArrayList<>();

        Session session = null;
        
        try 
        {
            List<Supplier> suppliers = new SupplierManager().find(supplierName);

            session = SessionFactoryUtil.getInstance().getCurrentSession();
            session.beginTransaction();
            
            for (Supplier supplier : suppliers) {
                List<HibReturn> hibReturns = session.createCriteria(HibReturn.class).add(Restrictions.like("supplierId", supplier.getSupplierId())).list();
                for (HibReturn dbReturn : hibReturns) {
                    Set<ReturnDetails> details = new HashSet<>();
                    for (HibReturnDetails hibReturnDetails : dbReturn.getDetails()) {
                        details.add(new ReturnDetails(hibReturnDetails.getId().getProductId(),
                                hibReturnDetails.getAmount()));
                    }
                    Order order = orderManager.find(dbReturn.getOrderId());
                    Return returnOb = new Return(supplier, order, dbReturn.getReturnDate(), details);
                    returnOb.setReturnId(dbReturn.getReturnId());
                    returns.add(returnOb);
                }
            }


            return returns;
        }
        catch (Exception e) {

            logger.log(Level.INFO, "Error listando devoluciones para el proveedor " + supplierName, e.getMessage());

            throw new IllegalStateException("Error al listar", e);
        }
        finally {
            if (session != null && session.isOpen()) {

                session.close();
            }
        }
    }

    @Override
    public List<Return> findByOrder(Order order)
    {
        List<Return> returns = new ArrayList<>();

        Session session = null;

        try {
            session = SessionFactoryUtil.getInstance().getCurrentSession();
            session.beginTransaction();

            List<HibReturn> hibReturns = session.createCriteria(HibReturn.class).add(Restrictions.like("orderId", order.getOrderId())).list();
            for (HibReturn dbReturn : hibReturns) {
                Set<ReturnDetails> details = new HashSet<>();
                for (HibReturnDetails hibReturnDetails : dbReturn.getDetails()) {
                    details.add(new ReturnDetails(hibReturnDetails.getId().getProductId(),
                            hibReturnDetails.getAmount()));
                }
                Supplier supplier = supplierManager.findById(dbReturn.getSupplierId());
                Return returnOb = new Return(supplier, order, dbReturn.getReturnDate(), details);
                returnOb.setReturnId(dbReturn.getReturnId());
                returns.add(returnOb);
            }

            return returns;
        }
        catch (Exception e) {

            logger.log(Level.INFO, "Error buscando devoluciones para la compra " + order.getOrderId(), e.getMessage());

            throw new IllegalStateException("Error buscando devoluciones para la compra " + order.getOrderId(), e);
        }
        finally {
            if (session != null && session.isOpen()) {

                session.close();
            }
        }
    }
}
